#ifndef Utilities_h__
#define Utilities_h__

#include "stdafx.h"
#include <iterator>

typedef cv::Point2f					Keypoint;
typedef std::vector<Keypoint>		KeypointList;
typedef std::vector<size_t>			KeypointIdList;
typedef std::vector<unsigned char>	StatusVector;
typedef std::vector<float>			ErrorVector;
typedef std::unique_ptr<cv::Mat>	MatUniqPtr;
typedef std::vector< int >			CircROI;

//static inline int CV_FOURCC(char c1, char c2, char c3, char c4)
//{
//	return (c1 & 255) + ((c2 & 255) << 8) + ((c3 & 255) << 16) + ((c4 & 255) << 24);
//}

void vesselnessMorphology(const cv::Mat& img, cv::Mat& vessIm, int morph_size = 9, int kernel_size = 5);

cv::Mat* mergeImages(int nArgs, ...);

cv::Mat histCalc256( const cv::Mat& img, const cv::Mat& mask );

double compareHistArray(const std::vector<MatUniqPtr>& array1, const std::vector<MatUniqPtr>& array2);

float getHistBinVal( const cv::Mat& hist, const int binNum );

float getFreqOfBin( const cv::Mat& histogram );

float shannonEntropy( const cv::Mat& Im,  const cv::Mat& mask);

float shannonEntropy( const cv::Mat& Im);

std::vector< cv::Mat > splitFrame( const cv::Mat& img );

template <typename T> std::string toString( const T& t ){ std::ostringstream os; os<<t; return os.str(); };

cv::Mat hessianFilter( cv::Mat &inputImage, int sigma );

std::vector< cv::KeyPoint > keypointFAST(const cv::Mat &inputImage, const cv::Mat &mask = cv::Mat());

std::vector< cv::KeyPoint > keypointTomasi( const cv::Mat &inputImage, const cv::Mat &mask = cv::Mat());

std::vector< cv::KeyPoint > keypointORB( const cv::Mat &inputImage, const cv::Mat &mask = cv::Mat());

std::vector< cv::KeyPoint > keypointBRISK( const cv::Mat &inputImage, const cv::Mat &mask /*= cv::Mat()*/ ); 

//cv::Mat descriptorORB( const cv::Mat &inputImage, const std::vector< cv::KeyPoint > &keypoint, const cv::Mat &mask /*= cv::Mat()*/ );

cv::Mat descriptorFREAK( const cv::Mat &inputImage, std::vector< cv::KeyPoint > &keypoint, const cv::Mat &mask /*= cv::Mat() */ );

cv::Mat descriptorBRISK( const cv::Mat &inputImage, std::vector<cv::KeyPoint> keypoint, const cv::Mat &mask );

cv::Mat& keypoint2Image( cv::Mat &inputImage, KeypointList &keypoints, StatusVector &status = StatusVector(), ErrorVector& errors = ErrorVector() , cv::Matx33d &H = cv::Matx33d::eye());

void showImageChannels( char *title, cv::Mat &inputImage, cv::Mat &frame1, cv::Mat &frame2, cv::Mat &frame3 );

cv::Mat customEdge( const cv::Mat& inputImage, int scale = 1, int delta = 0 );

int contrastStretch( int x, int r1, int r2, int s1, int s2 );

cv::Mat LoGFilter( cv::Mat &inputImage );

void histogramEqualization(cv::Mat &input, cv::Mat &output);

cv::Mat SURFkeypoints( cv::Mat &inputImage );

KeypointList keypoint2point( std::vector< cv::KeyPoint > keypoints );

std::string getImgType(int imgTypeInt);

template<typename T>
inline std::vector<T> erase_indices(const std::vector<T>& data, std::vector<size_t>& indicesToDelete/* can't assume copy elision, don't pass-by-value */)
{
	if(indicesToDelete.empty())
		return data;

	std::vector<T> ret;
	ret.reserve(data.size() - indicesToDelete.size());

	std::sort(indicesToDelete.begin(), indicesToDelete.end());

	// new we can assume there is at least 1 element to delete. copy blocks at a time.
	std::vector<T>::const_iterator itBlockBegin = data.begin();
	for(std::vector<size_t>::const_iterator it = indicesToDelete.begin(); it != indicesToDelete.end(); ++ it)
	{
		std::vector<T>::const_iterator itBlockEnd = data.begin() + *it;
		if(itBlockBegin != itBlockEnd)
		{
			std::copy(itBlockBegin, itBlockEnd, std::back_inserter(ret));
		}
		itBlockBegin = itBlockEnd + 1;
	}

	// copy last block.
	if(itBlockBegin != data.end())
	{
		std::copy(itBlockBegin, data.end(), std::back_inserter(ret));
	}

	return ret;
}
#endif // Utilities_h__

void getMask( cv::Mat &inputImage_R,cv::Mat &inputImage_H, cv::Mat &mask );

// Additions to RetinaTracker

std::vector< cv::KeyPoint > getCircularROI( cv::Mat inputImage, cv::Mat &mask );

CircROI doubleDerivative( CircROI roiSignal, int sum );

bool InitializeVector();

void DoGFilter( cv::Mat inputImage, cv::Mat outputImage );

void convolveDFT( cv::Mat A, cv::Mat B, cv::Mat C);